﻿using System.Data;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using POS.BusinessEntities;
using POS.DataObjects;

namespace POS.DataObjectsTest
{   
    [TestClass]
    public class DOSeguridadTest
    {
        #region Declarations
        private Database db;
        private const string testUser = "TestUser";
        private const string adminUser = "Admin";
        DataTable permisos;

        private const string columnaCodigo = "codigo";
        private const string columnaNombre = "nombre";
        private const string columnaTipo = "tipo";
        private const string columnaActivo = "activo";
        private const string columnaUsuarioId = "usuarioId";

        #endregion

        #region Properties: Non-Public
        
        private Database Db 
        { 
            get
            {
                if (db == null)
                    db = DatabaseFactory.CreateDatabase();
                return db;
            }
        }

        #endregion
        
        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion
        
        [TestMethod]
        public void GetMenuWithNoEntries()
        {
            CleanupPermissionsData();

            // Exercise SUT
            var expectedMenu = new BEPermisoCollection();
            var actualMenu = DOSeguridad.GetMenu(testUser);

            // Verify
            Assert.IsNotNull(actualMenu);
            Assert.AreEqual(expectedMenu.Count, actualMenu.Count);
            Assert.AreEqual(expectedMenu, actualMenu);

            // Tear down
            CleanupPermissionsData();
        }

        [TestMethod]
        public void GetMenuForRegularUser()
        {   
            SetupPermissionsMenu();

            // Exercise SUT
            var expectedMenu = CreateTestPermission(testUser, PermisoTipo.Menu);
            var actualMenu = DOSeguridad.GetMenu(testUser);
            
            // Verify
            Assert.IsNotNull(actualMenu);
            Assert.AreEqual(expectedMenu.Count, actualMenu.Count);
            Assert.AreEqual(expectedMenu, actualMenu);
            
            // Tear down
            CleanupPermissionsData();
        }

        [TestMethod]
        public void GetMenuForAdminUser()
        {
            SetupPermissionsMenu();

            // Exercise SUT
            var expectedMenu = CreateTestPermission(adminUser, PermisoTipo.Menu);
            var actualMenu = DOSeguridad.GetMenu(adminUser);

            // Verify
            Assert.IsNotNull(actualMenu);
            Assert.AreEqual(expectedMenu.Count, actualMenu.Count);
            Assert.AreEqual(expectedMenu, actualMenu);

            // Tear down
            CleanupPermissionsData();
        }


        #region Methods

        private BEPermisoCollection CreateTestPermission(string usuarioId, PermisoTipo tipo)
        {
            var misPermisos = new BEPermisoCollection();
            BEPermiso permiso;
            var tipoMenu = PermisoTipo.Menu; 
            var tipoAccion = PermisoTipo.Accion; 
            
            foreach (DataRow row in permisos.Rows)
            {
                if ((usuarioId == adminUser || (usuarioId == row[columnaUsuarioId].ToString())) &&
                    (row[columnaActivo].ToString() == "1") &&
                    (row[columnaTipo].ToString() == (tipo == PermisoTipo.Accion ? "A" : "M")))
                {
                    permiso = new BEPermiso();
                    permiso.Codigo = row[columnaCodigo].ToString();
                    permiso.Nombre = row[columnaNombre].ToString();
                    permiso.Tipo = row[columnaTipo].ToString() == "A" ? tipoAccion : tipoMenu;
                    misPermisos.Add(permiso);
                }
            }
            return misPermisos;
        }

        private void SetupPermissionsMenu()
        {
            CleanupPermissionsData();
                
            // Usuario
            string sql = "Insert into usuario (empresaId, usuarioId, Nombre, Clave) Values (1,'" + testUser + "','', '')";
            Db.ExecuteNonQuery(CommandType.Text, sql);

            // Permiso
            sql = "insert into permiso (codigo,nombre,tipo,activo) values ('m_adm','T-Administración','M',1)";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permiso (codigo,nombre,tipo,activo) values ('m_adm_seg','T-Seguridad','M',1)";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permiso (codigo,nombre,tipo,activo) values ('m_adm_est','T-Estaciones','M',1)";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permiso (codigo,nombre,tipo,activo) values ('m_ven','T-Ventas','M',0)";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permiso (codigo,nombre,tipo,activo) values ('a_des','T-Descuento','A',1)";
            Db.ExecuteNonQuery(CommandType.Text, sql);

            // Permiso por usuario
            sql = "insert into permisoxusuario (usuarioId, permisoId, AsignadoPor) select  '" + testUser + "', permisoId,  '" + testUser + "' from permiso where codigo = 'm_adm'";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permisoxusuario (usuarioId, permisoId, AsignadoPor) select  '" + testUser + "', permisoId,  '" + testUser + "' from permiso where codigo = 'm_adm_seg'";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "insert into permisoxusuario (usuarioId, permisoId, AsignadoPor) select  '" + testUser + "', permisoId,  '" + testUser + "' from permiso where codigo = 'a_des'";
            Db.ExecuteNonQuery(CommandType.Text, sql);

            // "Universo" de permisos
            permisos = new DataTable();
            permisos.Columns.Add(columnaCodigo);
            permisos.Columns.Add(columnaNombre);
            permisos.Columns.Add(columnaTipo);
            permisos.Columns.Add(columnaActivo);
            permisos.Columns.Add(columnaUsuarioId);
            permisos.Rows.Add(new object[] { "m_adm", "T-Administración", "M", 1, testUser });
            permisos.Rows.Add(new object[] { "m_adm_seg", "T-Seguridad", "M", 1, testUser });
            permisos.Rows.Add(new object[] { "m_adm_est", "T-Estaciones", "M", 1, "" });
            permisos.Rows.Add(new object[] { "m_ven", "T-Ventas", "M", 0, "" });
            permisos.Rows.Add(new object[] { "m_ven", "T-Descuento", "A", 1, testUser });
        }

        private void CleanupPermissionsData()
        {
            string sql = "delete from permisoXUsuario where usuarioId = '" + testUser + "'";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "delete from permiso where nombre like 'T-%'";
            Db.ExecuteNonQuery(CommandType.Text, sql);
            sql = "delete from usuario where UsuarioId = '" + testUser + "'";
            Db.ExecuteNonQuery(CommandType.Text, sql);
        }

        #endregion
    }
}
